package se.webbzon.boltzmann.npc;

import se.webbzon.boltzmann.game.character.AbstractCharacter;
import se.webbzon.boltzmann.game.character.CharacterException;
import se.webbzon.boltzmann.game.npc.StandingDuty;
import se.webbzon.oschi01.collision3d.CollisionCube3D;
import se.webbzon.oschi01.worldarea.WorldArea;
import se.webbzon.oschi01.worldobject.WorldObject;

public abstract class AbstractNPC extends AbstractCharacter {
	
	// The shadow of the non-player character
	private final NPCShadow shadow;
	
	// The duty of the non-player character
	private NPCDuty duty;
	
	// The walk speed and run speed of the non-player character
	private double walkSpeed, runSpeed;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public AbstractNPC(	int registeredMethods,
						String characterTextureSetName,
						double walkSpeed, double runSpeed) throws CharacterException {
		super(	registeredMethods | WorldObject.onCreate | 
				WorldObject.onStep | WorldObject.onDestroy,
				characterTextureSetName);
		this.walkSpeed = walkSpeed;
		this.runSpeed = runSpeed;
		shadow = new NPCShadow(this);
		duty = null;
		
		setMask(new CollisionCube3D());
		setSize(32,32,32);
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Forces the non-player character to perform the given duty
	 * regardless of the priority of the duty. **/
	public void forceDuty(NPCDuty duty) {
		setDuty(duty);
	}
	
	/** Assigns a duty to the non-player character. **/
	public void assignDuty(NPCDuty duty) {
		if (this.duty == null || duty.getPriority() >= this.duty.getPriority())
			setDuty(duty);
	}
	
	/** Dismisses the current duty of the non-player character. **/
	public void dismissDuty() {
		duty = null;
	}
	
	/** Returns the duty associated with the non-player character. **/
	public NPCDuty getDuty() {
		return duty;
	}
	
	/** Returns the walk speed for the non-player character. **/
	public double getWalkSpeed() {
		return walkSpeed;
	}
	
	/** Returns the run speed for the non-player character. **/
	public double getRunSpeed() {
		return runSpeed;
	}
	
	@Override public void onCreate(WorldArea world) {
		shadow.launch(world);
		shadow.setPosition(getX(), getY()-getHeight()/2, getZ());
		
		// Set the default duty if none is assigned
		if (duty == null) {
			duty = new StandingDuty(this);
			duty.onBegin();
		}
	}
	
	@Override public void onDestroy(WorldArea world) {
		shadow.terminate(world);
	}
	
	@Override public void onStep(WorldArea world) {
		duty.onStep();
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Sets the duty for the non-player character. **/
	private void setDuty(NPCDuty duty) {
		if (duty != this.duty) {
			if (this.duty != null)
				this.duty.onEnd();
			this.duty = duty;
			duty.onBegin();
		}
	}

}
